SPM: Allow preemption in non-blocking requests
authorAntonio Nino Diaz <[email protected]>
Tue, 3 Jul 2018 15:54:33 +0000 (16:54 +0100)
committerAntonio Nino Diaz <[email protected]>
Tue, 11 Dec 2018 15:04:24 +0000 (15:04 +0000)
Change-Id: I1fdc2285a3f6517a715ad6159322543fd5a37a37
Signed-off-by: Antonio Nino Diaz <[email protected]>
services/std_svc/spm/spci.c
services/std_svc/spm/spm_main.c
services/std_svc/spm/spm_private.h

index 41b0b00c34a74c6db9e2a4e460d95181cee2e798..5e4ff918391be80c7e598a5351b3bebca3264243 100644 (file)
@@ -348,7 +348,7 @@ static uint64_t spci_service_request_blocking(void *handle,
        }
 
        /* Jump to the Secure Partition. */
-       rx0 = spm_sp_synchronous_entry(sp_ctx);
+       rx0 = spm_sp_synchronous_entry(sp_ctx, 0);
 
        /* Verify returned value */
        if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
@@ -454,8 +454,14 @@ static uint64_t spci_service_request_start(void *handle,
        /* Save the Normal world context */
        cm_el1_sysregs_context_save(NON_SECURE);
 
+       /*
+        * This request is non-blocking and needs to be interruptible by
+        * non-secure interrupts. Enable their routing to EL3 during the
+        * processing of the Secure Partition's service on this core.
+        */
+
        /* Jump to the Secure Partition. */
-       uint64_t ret = spm_sp_synchronous_entry(sp_ctx);
+       uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
 
        /* Verify returned values */
        if (ret == SPRT_PUT_RESPONSE_AARCH64) {
@@ -480,7 +486,8 @@ static uint64_t spci_service_request_start(void *handle,
                         */
                        panic();
                }
-       } else if (ret != SPRT_YIELD_AARCH64) {
+       } else if ((ret != SPRT_YIELD_AARCH64) &&
+                  (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
                ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
                panic();
        }
@@ -554,8 +561,14 @@ static uint64_t spci_service_request_resume(void *handle, u_register_t x1,
        /* Save the Normal world context */
        cm_el1_sysregs_context_save(NON_SECURE);
 
+       /*
+        * This request is non-blocking and needs to be interruptible by
+        * non-secure interrupts. Enable their routing to EL3 during the
+        * processing of the Secure Partition's service on this core.
+        */
+
        /* Jump to the Secure Partition. */
-       uint64_t ret = spm_sp_synchronous_entry(sp_ctx);
+       uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
 
        /* Verify returned values */
        if (ret == SPRT_PUT_RESPONSE_AARCH64) {
@@ -580,7 +593,8 @@ static uint64_t spci_service_request_resume(void *handle, u_register_t x1,
                         */
                        panic();
                }
-       } else if (ret != SPRT_YIELD_AARCH64) {
+       } else if ((ret != SPRT_YIELD_AARCH64) &&
+                  (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
                ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
                panic();
        }
index 050c66cc1bd2326bedace54ff54413c1e3e877b6..5d3cc1a323d0750cf6e3beef3ff269f87e2ddd0d 100644 (file)
@@ -11,6 +11,7 @@
 #include <debug.h>
 #include <ehf.h>
 #include <errno.h>
+#include <interrupt_mgmt.h>
 #include <platform.h>
 #include <runtime_svc.h>
 #include <smccc.h>
@@ -167,7 +168,7 @@ int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
  * This function takes an SP context pointer and performs a synchronous entry
  * into it.
  ******************************************************************************/
-uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
+uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt)
 {
        uint64_t rc;
        unsigned int linear_id = plat_my_core_pos();
@@ -186,6 +187,12 @@ uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
        tlbivmalle1();
        dsbish();
 
+       if (can_preempt == 1) {
+               enable_intr_rm_local(INTR_TYPE_NS, SECURE);
+       } else {
+               disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+       }
+
        /* Enter Secure Partition */
        rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
 
@@ -215,6 +222,20 @@ __dead2 void spm_sp_synchronous_exit(uint64_t rc)
        panic();
 }
 
+/*******************************************************************************
+ * This function is the handler registered for Non secure interrupts by the SPM.
+ * It validates the interrupt and upon success arranges entry into the normal
+ * world for handling the interrupt.
+ ******************************************************************************/
+static uint64_t spm_ns_interrupt_handler(uint32_t id, uint32_t flags,
+                                         void *handle, void *cookie)
+{
+       /* Check the security state when the exception was generated */
+       assert(get_interrupt_src_ss(flags) == SECURE);
+
+       spm_sp_synchronous_exit(SPM_SECURE_PARTITION_PREEMPTED);
+}
+
 /*******************************************************************************
  * Jump to each Secure Partition for the first time.
  ******************************************************************************/
@@ -235,7 +256,7 @@ static int32_t spm_init(void)
 
                ctx->state = SP_STATE_RESET;
 
-               rc = spm_sp_synchronous_entry(ctx);
+               rc = spm_sp_synchronous_entry(ctx, 0);
                if (rc != SPRT_YIELD_AARCH64) {
                        ERROR("Unexpected return value 0x%llx\n", rc);
                        panic();
@@ -258,10 +279,29 @@ int32_t spm_setup(void)
        sp_context_t *ctx;
        void *sp_base, *rd_base;
        size_t sp_size, rd_size;
+       uint64_t flags = 0U;
 
        /* Disable MMU at EL1 (initialized by BL2) */
        disable_mmu_icache_el1();
 
+       /*
+        * Non-blocking services can be interrupted by Non-secure interrupts.
+        * Register an interrupt handler for NS interrupts when generated while
+        * the CPU is in secure state. They are routed to EL3.
+        */
+       set_interrupt_rm_flag(flags, SECURE);
+
+       uint64_t rc_int = register_interrupt_type_handler(INTR_TYPE_NS,
+                               spm_ns_interrupt_handler, flags);
+       if (rc_int) {
+               ERROR("SPM: Failed to register NS interrupt handler with rc = %llx\n",
+                     rc_int);
+               panic();
+       }
+
+       /*
+        * Setup all Secure Partitions.
+        */
        unsigned int i = 0U;
 
        while (1) {
index 7216003bfd62c283671153c4d6b2789d8059b24c..5414e83483d5e11970f72f0499192192f78273d7 100644 (file)
@@ -29,6 +29,9 @@
 #define SP_C_RT_CTX_SIZE       0x60
 #define SP_C_RT_CTX_ENTRIES    (SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
 
+/* Value returned by spm_sp_synchronous_entry() when a partition is preempted */
+#define SPM_SECURE_PARTITION_PREEMPTED U(0x1234)
+
 #ifndef __ASSEMBLY__
 
 #include <spinlock.h>
@@ -68,7 +71,7 @@ typedef struct sp_context {
 } sp_context_t;
 
 /* Functions used to enter/exit a Secure Partition synchronously */
-uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx);
+uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt);
 __dead2 void spm_sp_synchronous_exit(uint64_t rc);
 
 /* Assembly helpers */